package com.zshan.clinic.common.util.lock;

import com.zshan.clinic.common.exception.BusinessFailException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * redisson工具类
 * @author lichen
 */
@Slf4j
@Component
public class RedissonLockUtil {

    private final RedissonClient redissonClient;

    public RedissonLockUtil(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 尝试获取锁（默认超时时间 10 秒，锁租期 30 秒）
     */
    public boolean tryLock(String lockKey) {
        return tryLock(lockKey, 10, 30, TimeUnit.SECONDS);
    }

    /**
     * 尝试加锁
     */
    public boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("尝试获取锁中断，lockKey={}", lockKey, e);
            return false;
        } catch (Exception e) {
            log.error("尝试获取锁异常，lockKey={}", lockKey, e);
            return false;
        }
    }

    /**
     * 解锁
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("成功释放redis分布式锁lockKey:{},当前线程ID:{}",lockKey,Thread.currentThread().getId());
            }
        } catch (Exception e) {
            log.error("释放锁失败，lockKey={}，错误：{}", lockKey, e.getMessage(), e);
        }
    }

    /**
     * 执行带锁的逻辑（无返回值）
     */
    public void execute(String lockKey, long waitTime, long leaseTime, Runnable task) {
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        try {
            locked = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            if (!locked) {
                throw new BusinessFailException("系统繁忙，请稍后重试");
            }
            log.info("成功获取到redis分布式锁lockKey:{},当前线程ID:{}",lockKey,Thread.currentThread().getId());
            task.run();
        } catch (BusinessFailException e) {
            log.warn("业务失败：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("执行分布式锁任务失败，lockKey={}", lockKey, e);
            throw new BusinessFailException("网络繁忙，请稍后再试");
        } finally {
            if (locked && lock.isHeldByCurrentThread()) {
                unlock(lockKey);
            }
        }
    }

    /**
     * 执行带锁的逻辑（有返回值）
     */
    public <T> T execute(String lockKey, long waitTime, long leaseTime, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        try {
            locked = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            if (!locked) {
                throw new BusinessFailException("系统繁忙，请稍后重试");
            }
            log.info("成功获取到redis分布式锁lockKey:{},当前线程ID:{}",lockKey,Thread.currentThread().getId());
            return supplier.get();
        } catch (BusinessFailException e) {
            log.warn("业务失败：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("执行分布式锁任务失败，lockKey={}", lockKey, e);
            throw new BusinessFailException("系统异常，请稍后再试");
        } finally {
            if (locked && lock.isHeldByCurrentThread()) {
                unlock(lockKey);
            }
        }
    }
}

